package com.dimples.controller.system;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dimples.common.annotation.OpsLog;
import com.dimples.common.entity.SecurityUser;
import com.dimples.common.enums.CodeMsgEnum;
import com.dimples.common.enums.LoggingTypeEnum;
import com.dimples.common.enums.OpsLogTypeEnum;
import com.dimples.common.exception.DataException;
import com.dimples.common.page.metadata.Page;
import com.dimples.common.service.DimplesJwtTokenServiceImpl;
import com.dimples.common.transport.QueryRequest;
import com.dimples.common.transport.Result;
import com.dimples.common.util.HttpContextUtil;
import com.dimples.controller.view.BaseWebController;
import com.dimples.system.entity.Logging;
import com.dimples.system.entity.SysFile;
import com.dimples.system.entity.SysUser;
import com.dimples.system.service.LoggingService;
import com.dimples.system.service.SysFileService;
import com.dimples.system.service.SysUserService;
import com.dimples.system.vo.UserVO;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;

import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.List;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2021/6/26
 */
@Slf4j
@Api(tags = "用户管理")
@Validated
@RestController
@RequestMapping(value = BaseWebController.API_SYSTEM_PREFIX)
@RequiredArgsConstructor
public class SysUserController {

    private final DimplesJwtTokenServiceImpl tokenService;
    private final SysUserService sysUserService;
    private final SysFileService sysFileService;
    private final LoggingService loggingService;

    @ApiOperation(value = "获取用户列表")
    @ApiOperationSupport(order = 1)
    @OpsLog(value = "获取用户列表", type = OpsLogTypeEnum.SELECT)
    @GetMapping("user")
    @PreAuthorize("@auth.hasPerm('user:view')")
    public Result<SysUser> findUser(SysUser sysUser, QueryRequest queryRequest) {
        Page<SysUser> result = this.sysUserService.findUser(sysUser, queryRequest);
        return Result.success(result);
    }

    @ApiOperation(value = "获取用户详情")
    @ApiOperationSupport(order = 2)
    @OpsLog(value = "获取用户详情", type = OpsLogTypeEnum.SELECT)
    @GetMapping("user/{userId}")
    @PreAuthorize("@auth.hasPerm('user:view')")
    public Result<UserVO> getUser(@PathVariable @NotNull(message = "不能为空") Long userId) {
        UserVO result = this.sysUserService.getUser(userId);
        return Result.success(result);
    }

    @ApiOperation(value = "获取用户Token信息")
    @ApiOperationSupport(order = 3)
    @OpsLog(value = "获取用户Token信息", type = OpsLogTypeEnum.SELECT)
    @GetMapping("user/cache")
    @PreAuthorize("@auth.hasPerm('user:view')")
    public Result<SecurityUser> getUser() {
        return Result.success(tokenService.getLoginUserFromToken(HttpContextUtil.getRequest()));
    }

    @ApiOperation(value = "获取用户权限")
    @ApiOperationSupport(order = 3)
    @OpsLog(value = "获取用户权限", type = OpsLogTypeEnum.SELECT)
    @GetMapping("user/perm")
    @PreAuthorize("@auth.hasPerm('user:perm:view')")
    public Result<SecurityUser> findUserPerm() {
        SecurityUser currentUser = tokenService.getLoginUserFromToken(HttpContextUtil.getRequest());
        return Result.success(currentUser);
    }

    @ApiOperation(value = "获取用户登陆记录")
    @ApiOperationSupport(order = 3)
    @OpsLog(value = "获取用户登陆记录", type = OpsLogTypeEnum.SELECT)
    @GetMapping("user/login/log")
    @PreAuthorize("@auth.hasPerm('user:login:log')")
    public Result<Logging> findUserLoginLog() {
        List<Logging> loginLogs = this.loggingService.list(Wrappers
                .lambdaQuery(Logging.class)
                .eq(Logging::getOperateName, tokenService.getUsernameFromToken(HttpContextUtil.getRequest()))
                .eq(Logging::getLoggingType, LoggingTypeEnum.LOGIN.name())
                .orderByDesc(Logging::getCreateTime));
        return Result.success(loginLogs);
    }

    @ApiOperation(value = "修改用户状态")
    @ApiOperationSupport(order = 5)
    @OpsLog(value = "修改用户状态", type = OpsLogTypeEnum.UPDATE)
    @PutMapping("user/status")
    @PreAuthorize("@auth.hasPerm('user:status:edit')")
    public Result<SysUser> updateUserStatus(@RequestBody SysUser sysUser) {
        this.sysUserService.updateById(sysUser);
        return Result.success();
    }


    @ApiOperation(value = "新增用户")
    @ApiOperationSupport(order = 7)
    @OpsLog(value = "新增用户", type = OpsLogTypeEnum.ADD)
    @PostMapping("user")
    @PreAuthorize("@auth.hasPerm('user:add')")
    public Result<SysUser> saveUser(@Valid @RequestBody SysUser sysUser) {
        this.sysUserService.saveUser(sysUser);
        return Result.success();
    }

    @PostMapping("user/register")
    public Result<SysUser> register(
            @NotBlank(message = "不能为空") String username,
            @NotBlank(message = "不能为空") String password) {
        SysUser user = this.sysUserService.findByName(username);
        if (user != null) {
            throw new DataException("该用户名已存在");
        }
        this.sysUserService.register(username, password);
        return Result.success();
    }

    @ApiOperation(value = "编辑用户")
    @ApiOperationSupport(order = 9)
    @OpsLog(value = "编辑用户", type = OpsLogTypeEnum.UPDATE)
    @PutMapping("user")
    @PreAuthorize("@auth.hasPerm('user:edit')")
    public Result<SysUser> updateUser(@Valid @RequestBody SysUser sysUser) {
        this.sysUserService.updateUser(sysUser);
        return Result.success();
    }

    @ApiOperation(value = "删除用户")
    @ApiOperationSupport(order = 7)
    @OpsLog(value = "删除用户", type = OpsLogTypeEnum.DELETE)
    @DeleteMapping("user/{userId}")
    @PreAuthorize("@auth.hasPerm('user:delete')")
    public Result<SysUser> deleteUser(@PathVariable @NotNull(message = "不能为空") Long userId) {
        this.sysUserService.deleteUser(userId);
        return Result.success();
    }

    @ApiOperation(value = "批量删除用户")
    @ApiOperationSupport(order = 8)
    @OpsLog(value = "批量删除用户", type = OpsLogTypeEnum.DELETE)
    @DeleteMapping("user/batch/{userIds}")
    @PreAuthorize("@auth.hasPerm('user:delete')")
    public Result<SysUser> deleteUsers(@PathVariable @NotBlank(message = "不能为空") String userIds) {
        this.sysUserService.deleteUsers(userIds);
        return Result.success();
    }

    @ApiOperation(value = "下载用户头像")
    @ApiOperationSupport(order = 10)
    @OpsLog(value = "下载用户头像", type = OpsLogTypeEnum.DOWNLOAD)
    @GetMapping("user/avatar/{avatarName}")
    public void downloadAvatar(@PathVariable String avatarName) throws IOException {
        LambdaQueryWrapper<SysFile> lambdaQuery = Wrappers.lambdaQuery(SysFile.class);
        lambdaQuery.eq(SysFile::getFileId, avatarName).or().eq(SysFile::getFileName, avatarName);
        SysFile file = this.sysFileService.getOne(lambdaQuery);
        Result.buildResponse(HttpContextUtil.getResponse()
                , StrUtil.equalsAnyIgnoreCase(FileUtil.getType(FileUtil.file(file.getFilePath())), "PNG") ? MediaType.IMAGE_PNG_VALUE : MediaType.IMAGE_JPEG_VALUE
                , CodeMsgEnum.SUCCESS.getCode()
                , FileUtil.readBytes(file.getFilePath()));
    }

    @ApiOperation(value = "修改用户头像")
    @ApiOperationSupport(order = 11)
    @ApiImplicitParam(name = "avatarId", value = "头像id", paramType = "query", required = true)
    @OpsLog(value = "修改用户头像", type = OpsLogTypeEnum.UPDATE)
    @PutMapping("user/avatar/{avatarId}")
    public Result<SecurityUser> updateUserAvatar(@NotBlank(message = "不能为空") @PathVariable String avatarId) {
        SecurityUser sysUser = this.sysUserService.updateUserAvatar(avatarId);
        return Result.success(sysUser);
    }

    @ApiOperation(value = "修改用户密码")
    @ApiOperationSupport(order = 12)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "oldPassword", value = "旧密码", paramType = "query", required = true),
            @ApiImplicitParam(name = "newPassword", value = "新密码", paramType = "query", required = true)
    })
    @OpsLog(value = "修改用户密码", type = OpsLogTypeEnum.UPDATE)
    @PutMapping("user/password")
    public Result<SysUser> updateUserPassword(@NotBlank(message = "不能为空") String oldPassword, @NotBlank(message = "不能为空") String newPassword) {
        this.sysUserService.updateUserPassword(oldPassword, newPassword);
        return Result.success();
    }
}
